/* 
 * Copyright 2013 Sébastien Mouquet.
 * 
 * This file is part of ECovoiturage.
 * 
 * ECovoiturage is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ECovoiturage is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ECovoiturage. If not, see http://www.gnu.org/licenses/.
 */
package com.smouquet.ecovoiturage.ui.page.root.trajetmidi;

import com.smouquet.ecovoiturage.core.bean.TrajetMidiFormBean;
import com.smouquet.ecovoiturage.core.domain.Lieu;
import com.smouquet.ecovoiturage.ui.NotificationUtil;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Validator;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.PropertyId;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.data.validator.RegexpValidator;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.util.ReflectTools;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.List;

/**
 *
 * @author sebastien.mouquet
 */
public class TrajetMidiForm extends GridLayout
                            implements Property.ValueChangeListener
{
    private static final int NB_COL = 4;
    private static final int NB_ROW = 4;
    
    @PropertyId("lieu")
    private ComboBox cbLieu;
    @PropertyId("lieuNom")
    private TextField tfLieuNom;
    @PropertyId("lieuAdresse")
    private TextField tfLieuAdresse;
    @PropertyId("heureDepart")
    private TextField tfHeureDepart;
    @PropertyId("heureRetour")
    private TextField tfHeureRetour;
    @PropertyId("informations")
    private TextArea taInformations;
    
    private FieldGroup fgForm;
    
    private List<Lieu> lieux;
    private TrajetMidiFormBean trajetMidi;
    
    /**
     * Constructeur à utiliser en cas de création d'un nouveau
     * trajet du midi.
     */
    public TrajetMidiForm()
    {
        super(NB_COL, NB_ROW);
        this.trajetMidi = new TrajetMidiFormBean();
        layout();
    }
    
    /**
     * Constructeur à utiliser en cas de création d'un nouveau
     * trajet du midi. Il prend également la liste des lieux pour
     * la <code>ComboBox</code>.
     * 
     * @param lieux Liste des lieux pour la <code>ComboBox</code>
     */
    public TrajetMidiForm(List<Lieu> lieux)
    {
        super(NB_COL, NB_ROW);
        this.lieux = lieux;
        this.trajetMidi = new TrajetMidiFormBean();
        layout();
    }
    
    
    public void setLieux(List<Lieu> lieux)
    {
        this.lieux = lieux;
        
        if(cbLieu != null) {
            prepareAndInstallCbLieuContainer();
        }
    }

    public TrajetMidiFormBean getTrajetMidi() {
        return trajetMidi;
    }

    public void setTrajetMidi(TrajetMidiFormBean trajetMidi)
    {
        this.trajetMidi = trajetMidi;
        
        if(trajetMidi != null) {
            prepareFieldGroup();
        }
    }
    
    public void doCommit()
    {
        try
        {
            fgForm.commit();
            
            fireEvent(new CommitEvent(this, trajetMidi));
            
        } catch(Validator.InvalidValueException ex) {
            NotificationUtil.showWarningNotification("Formulaire incomplet et/ou données invalides");
        } catch(FieldGroup.CommitException ex) {
            NotificationUtil.showWarningNotification("Formulaire incomplet et/ou données invalides");
        }
    }

    
    private void layout()
    {
        cbLieu = new ComboBox("Lieu (pour créer un nouveau lieu, n'en sélectionnez pas ici mais saisissez le nom et l'adresse ci-après)");
        cbLieu.setWidth(100, Unit.PERCENTAGE);
        cbLieu.setImmediate(true);
        cbLieu.setNewItemsAllowed(false);
        cbLieu.addValueChangeListener(this);
        prepareAndInstallCbLieuContainer();
        
        tfLieuNom = new TextField("Nom");
        tfLieuNom.setWidth(100, Unit.PERCENTAGE);
        tfLieuNom.setRequired(true);
        tfLieuNom.setMaxLength(80);
        tfLieuNom.setNullRepresentation("");
        
        tfLieuAdresse = new TextField("Adresse");
        tfLieuAdresse.setWidth(100, Unit.PERCENTAGE);
        tfLieuAdresse.setRequired(true);
        tfLieuAdresse.setMaxLength(250);
        tfLieuAdresse.setNullRepresentation("");
        
        tfHeureDepart = new TextField("Heure de départ");
        tfHeureDepart.setWidth(100, Unit.PERCENTAGE);
        tfHeureDepart.setRequired(true);
        tfHeureDepart.setMaxLength(5);
        tfHeureDepart.addValidator(new RegexpValidator("^\\d{2}:\\d{2}$", "Format de l'heure attendu : '00:00'"));
        tfHeureDepart.setNullRepresentation("");
        
        tfHeureRetour = new TextField("Heure de retour");
        tfHeureRetour.setWidth(100, Unit.PERCENTAGE);
        tfHeureRetour.setMaxLength(5);
        tfHeureRetour.addValidator(new RegexpValidator("^\\d{2}:\\d{2}$", "Format de l'heure attendu : '00:00'"));
        tfHeureRetour.setNullRepresentation("");
        
        taInformations = new TextArea("Précisions / Informations");
        taInformations.setWidth(100, Unit.PERCENTAGE);
        taInformations.setNullRepresentation("");
        
        addComponent(cbLieu, 0, 0, 3, 0);
        addComponent(tfLieuNom, 0, 1);
        addComponent(tfLieuAdresse, 1, 1, 3, 1);
        addComponent(tfHeureDepart, 0, 2, 1, 2);
        addComponent(tfHeureRetour, 2, 2, 3, 2);
        addComponent(taInformations, 0, 3, 3, 3);
        
        if(trajetMidi != null) {
            prepareFieldGroup();
        }
        
        setWidth(100, Unit.PERCENTAGE);
        setSpacing(true);
    }
    
    private void prepareAndInstallCbLieuContainer()
    {
        BeanItemContainer<Lieu> container = new BeanItemContainer<Lieu>(Lieu.class);
        
        for(Lieu l : lieux) {
            container.addItem(l);
        }
        
        cbLieu.setContainerDataSource(container);
        cbLieu.setItemCaptionMode(AbstractSelect.ItemCaptionMode.PROPERTY);
        cbLieu.setItemCaptionPropertyId("nom");
    }
    
    private void prepareFieldGroup()
    {
        fgForm = new FieldGroup(new BeanItem<TrajetMidiFormBean>(trajetMidi));
        fgForm.bindMemberFields(this);
    }

    
    @Override
    public void valueChange(ValueChangeEvent event)
    {
        Lieu lieu = (Lieu)event.getProperty().getValue();
        if(lieu != null) {
            tfLieuNom.setValue(lieu.getNom());
            tfLieuAdresse.setValue(lieu.getAdresse());
        } else {
            tfLieuNom.setValue(null);
            tfLieuAdresse.setValue(null);
        }
    }
    
    
    public static class CommitEvent extends Event
    {
        private TrajetMidiFormBean trajetMidi;
        
        public CommitEvent(Component source, TrajetMidiFormBean trajetMidi) {
            super(source);
            this.trajetMidi = trajetMidi;
        }

        public TrajetMidiFormBean getTrajetMidi() {
            return trajetMidi;
        }
    }
    
    public interface CommitListener extends Serializable
    {
        public static final Method METHOD = ReflectTools.findMethod(CommitListener.class, "onCommit", CommitEvent.class);
        
        void onCommit(CommitEvent event);
    }
    
    public void addCommitListener(CommitListener listener)
    {
        addListener(CommitEvent.class, listener, CommitListener.METHOD);
    }
    
    public void removeCommitListener(CommitListener listener)
    {
        addListener(CommitEvent.class, listener, CommitListener.METHOD);
    }
}
